home *** CD-ROM | disk | FTP | other *** search
- Imports System.Threading
-
- Module MainModule
-
- Sub Main()
- ' Run one of the Textxxxx procedures below by uncommenting only one statement
-
- 'TestThread()
- 'TestSuspendResume()
- 'TestJoin()
- 'TestInterrupt()
- 'TestThreadStatic()
- 'TestThreadLocalStorage()
- 'TestThreadData()
- 'TestEventNotifications()
- 'TestWrapperClass()
- 'TestSynchronizationProblem()
- 'TestSyncLock()
- 'TestSyncRoot()
- 'TestMonitorEnter()
- 'TestMonitorTryEnter()
- 'TestInterlocked()
- 'TestMutex()
- 'TestReaderWriterLock()
- 'TestAutoResetEvent()
- 'TestThreadPool()
- 'TestServerTimer()
- 'TestThreadingTimer()
- 'TestSynchronizationAttribute()
-
- ' You need these statements when running inside Visual Studio, so that
- ' the Console window doesn't disappear
- Console.WriteLine("")
- Console.WriteLine(">>> Press Enter to terminate the program <<<")
- Console.ReadLine()
- End Sub
-
- ' this procedure tests basic thread capabilities
-
- Sub TestThread()
- ' Create a new thread and define its starting point.
- Dim t As New Thread(New ThreadStart(AddressOf DoTheTask))
- ' Run the new thread.
- t.Start()
-
- ' Print some messages to the Console window.
- Dim i As Integer
- For i = 1 To 10
- Console.WriteLine("Msg #{0} from main thread (ID={1})", i, AppDomain.GetCurrentThreadId)
- ' Wait for .2 seconds.
- Thread.CurrentThread.Sleep(200)
- Next
- End Sub
-
- Sub DoTheTask()
- Dim i As Integer
- For i = 1 To 10
- Console.WriteLine("Msg #{0} from secondary thread (ID={1})", i, AppDomain.GetCurrentThreadId)
- ' wait for .2 seconds.
- Thread.CurrentThread.Sleep(200)
- Next
- End Sub
-
- ' this procedure tests suspending and resuming threads
-
- Sub TestSuspendResume()
- ' Define and start a new thread.
- Dim t As New Thread(AddressOf DoTheTask)
- t.Start()
- Thread.Sleep(500)
-
- ' Suspend the thread.
- Console.WriteLine("Suspending secondary thread.")
- t.Suspend()
- Thread.Sleep(500)
-
- ' Resume the thread.
- Console.WriteLine("Resuming secondary thread.")
- t.Resume()
- Thread.Sleep(500)
- ' ...
- ' Abort the thread.
- Console.WriteLine("Aborting secondary thread.")
- t.Abort()
- End Sub
-
- ' this procecure tests the Join method
-
- Sub TestJoin()
- Dim t As New Thread(AddressOf DoTheTask)
- t.Start()
- Console.WriteLine("Waiting for the secondary thread to terminate")
-
- ' Wait for the other thread to die.
- t.Join()
- Console.WriteLine("Resuming the main thread")
- Console.WriteLine("")
-
- t = New Thread(AddressOf DoTheTask)
- t.Start()
- Console.WriteLine("Starting another thread, again")
-
- ' Wait for the other thread to die, but print a message every second.
- Do Until t.Join(1000)
- Console.WriteLine("Waiting for the other thread to die...")
- Loop
- Console.WriteLine("Resuming the main thread")
- End Sub
-
- ' this procedure tests the Interrupt method
-
- Sub TestInterrupt()
- Dim t As New Thread(AddressOf DoTheTask2)
- t.Start()
- ' let it do some work, then interrupt it
- Thread.Sleep(500)
-
- Console.WriteLine("Interrupting the secondary thread")
- t.Interrupt()
- End Sub
-
- ' a secondary thread that protects itself from the interrupt method
-
- Sub DoTheTask2()
- Dim interrupted As Boolean
-
- ' emclose the entire working code in a Try block
- Try
- Dim i As Integer
- For i = 1 To 10
- Console.WriteLine("Msg #" & i.ToString & " from secondary thread")
- ' wait for .2 seconds.
- Thread.CurrentThread.Sleep(200)
- Next
- ' We get here if the timeout elapsed and no exception is thrown.
- ' (Not really necessary, because the variable is already False.)
- interrupted = False
- Catch ex As Exception
- interrupted = True
- Finally
- ' print a suitable message
- If interrupted Then
- Console.WriteLine("The thread was interrupted")
- Else
- Console.WriteLine("The thread terminated normally.")
- End If
- End Try
- End Sub
-
- ' this procedure tests the ThreadStatic attribute
-
- Sub TestThreadStatic()
- Dim threads(10) As Thread
- Dim i As Integer
-
- For i = 1 To 10
- ' Create a new thread
- threads(i) = New Thread(AddressOf DoTheTask3)
- ' set its Name property
- threads(i).Name = "thread #" & i.ToString
- ' run it
- threads(i).Start()
- Next
-
- ' wait until all threads end
- For i = 1 To 10
- threads(i).Join()
- Next
- End Sub
-
- ' a variable that isn't shared among thread
- <ThreadStatic()> Dim m_ThreadId As String
-
- Sub DoTheTask3()
- ' Initialize the m_ThreadId variable with thread name
- m_ThreadId = Thread.CurrentThread.Name
-
- ' signal that the thread has started
- Console.WriteLine(Thread.CurrentThread.Name & " has started")
- ' just wait for a while
- Thread.CurrentThread.Sleep(2000)
-
- ' check that the m_ThreadID property hasn't been changed by other threads
- If m_ThreadId = Thread.CurrentThread.Name Then
- Console.WriteLine("m_ThreadID hasn't changed for " & Thread.CurrentThread.Name)
- Else
- Console.WriteLine("m_ThreadID *has* changed for " & Thread.CurrentThread.Name)
- End If
- End Sub
-
- ' this procedure tests Thread Local Storage
-
- Sub TestThreadLocalStorage()
- ' Allocate a new unnamed TLS slot.
- Dim slot As LocalDataStoreSlot = Thread.AllocateDataSlot()
-
- ' The AllocateNamedDataSlot method fails if the slot exists already.
- Dim namedSlot As LocalDataStoreSlot = Thread.AllocateNamedDataSlot("id")
-
- ' The GetNamedDataSlot method returns a reference to an existing named slot
- ' or creates a new slot if necessary.
- Dim namedSlot2 As LocalDataStoreSlot = Thread.GetNamedDataSlot("id")
-
- ' Store a value in the slot created previously.
- Thread.SetData(slot, 123)
- ' ...
- ' Read the value back.
- Console.Write(Thread.GetData(slot)) ' => 123
-
- ' Destroys the slot named ID from all the threads in the current application.
- Thread.FreeNamedDataSlot("id")
- End Sub
-
- ' this procedure tests sharing data with a thread with DataClass
-
- Sub TestThreadData()
- Dim i As Integer
- Dim dc(9) As ThreadData
- Dim t As Thread
- Dim allDone As Boolean
-
- ' Create multiple threads.
- For i = 0 To 9
- ' Create a new data object and initialize its property
- dc(i) = New ThreadData()
- dc(i).Id = i + 1
- dc(i).Msg = "A message"
- ' Create a new thread and define its starting point.
- t = New Thread(AddressOf dc(i).DoTheTask)
- t.Start()
- Next
-
- ' Poll until all threads have completed.
- ' (Just an example that retrieves values from threads.)
- Do Until allDone
- Console.WriteLine("Waiting...")
- Thread.CurrentThread.Sleep(200)
- ' Check that all threads have set Done=True.
- allDone = True
- For i = 0 To 9
- allDone = allDone And dc(i).Done
- Next
- Loop
- End Sub
-
- ' this procedure tests using events for thread notifications
-
- ' NOTE: if you make this variable ThreadStatic, the program won't work any longer
- ' because each thread will decrement a different copy of the variable.
- '<ThreadStatic()> _
- Dim runningThreads As Integer
-
- Sub TestEventNotifications()
- Dim i As Integer
- Dim dc(4) As ThreadData2
- Dim t As Thread
-
- Thread.CurrentThread.Name = "Main thread"
-
- ' Create multiple threads.
- For i = 0 To 4
- ' Create a new data object and initialize its property
- dc(i) = New ThreadData2()
- dc(i).Id = i + 1
- dc(i).Msg = "A message"
- ' have this object's events point to the local event procedure
- AddHandler dc(i).TaskCompleted, AddressOf TaskCompleted
- ' Create a new thread and define its starting point.
- t = New Thread(AddressOf dc(i).DoTheTask)
- t.Name = "Thread #" & dc(i).Id.ToString
- t.Start()
- ' increment number of running threds
- runningThreads += 1
- Next
-
- ' Poll until all threads have completed.
- ' (Just an example that retrieves values from threads.)
- Do Until runningThreads = 0
- Console.WriteLine("Waiting...")
- Thread.CurrentThread.Sleep(200)
- Loop
- End Sub
-
- ' an event procedure that runs when another thread terminates
-
- Sub TaskCompleted(ByVal Sender As Object, ByVal endTime As Date)
- ' get the ID of the thread that terminated
- Dim id As Integer = CType(Sender, ThreadData2).Id
- ' display a message
- ' Console.WriteLine("Thread {0} terminated at {1}.", id, endTime)
- Console.WriteLine("Thread {0} terminated (Running on {1})", id, Thread.CurrentThread.Name)
- ' decrement counter of running threads.
- runningThreads -= 1
- End Sub
-
- ' this procedure tests the ThreadWrapperBase class
-
- Sub TestWrapperClass()
- Dim i As Integer
- Dim mytasks(10) As MyTask
-
- For i = 1 To 10
- ' Initialize thread data, then start the thread.
- mytasks(i) = New MyTask(i, "Message from thread")
- mytasks(i).Thread.Name = "Thread #" & CStr(i)
- mytasks(i).Start()
- Next
-
- ' Wait until all tasks have completed.
- For i = 1 To 10
- Do Until mytasks(i).Done
- Console.WriteLine("Waiting... (Main thread)")
- Thread.Sleep(200)
- Loop
- Next
- End Sub
-
- ' this procedure shows problems caused by lack of synchronization
-
- Sub TestSynchronizationProblem()
- ' Create five auxiliary threads.
- Dim i As Integer
- For i = 1 To 5
- Dim t As New Thread(AddressOf DoTheTask4)
- ' Assign a name to this thread, so that we can track its output.
- t.Name = "Thread #" & i.ToString
- t.Start()
- Next
- End Sub
-
- Sub DoTheTask4()
- ' Print a lot of information to the console window.
- Dim i As Integer
- For i = 1 To 100
- ' Split the output line in pieces.
- Console.Write("Message ")
- Console.Write("from ")
- Console.WriteLine(Thread.CurrentThread.Name)
- 'Thread.Sleep(20)
- Next
- End Sub
-
- ' this procedure shows the solution based on SyncLock
-
- Sub TestSyncLock()
- ' Create five auxiliary threads.
- Dim i As Integer
- For i = 1 To 5
- Dim t As New Thread(AddressOf DoTheTask5)
- ' Assign a name to this thread, so that we can track its output.
- t.Name = "Thread #" & i.ToString
- t.Start()
- Next
- End Sub
-
- ' The lock object (any non-Nothing value will do).
- Dim consoleLock As String = "lock me"
-
- Sub DoTheTask5()
- ' Print a lot of information to the console window.
- Dim i As Integer
- For i = 1 To 100
- SyncLock consoleLock
- ' Split the output line in pieces.
- Console.Write("Message ")
- Console.Write("from ")
- Console.WriteLine(Thread.CurrentThread.Name)
- End SyncLock
- Next
- End Sub
-
- ' this procedure tests the SyncRoot property
-
- Dim dblArr() As Double = {1.24, 456.9, 1.11, 99.34, 543.56}
-
- Sub TestSyncRoot()
- Dim t As New Thread(AddressOf DoTheTask6)
- t.Start()
- t.Join()
- End Sub
-
- Sub DoTheTask6()
- Dim sum As Double
- SyncLock dblArr.SyncRoot
- ' Inside this block access to the ArrayList is thread-safe.
- Dim d As Double
- For Each d In dblArr
- sum += d
- Next
- Console.WriteLine("sum is {0}", sum) ' => sum is 1102.15
- End SyncLock
- End Sub
-
- ' this procedure tests the Monitor.Enter / Exit methods
-
- Sub TestMonitorEnter()
- ' Create five auxiliary threads.
- Dim threads(5) As Thread
-
- Dim i As Integer
- For i = 1 To 5
- threads(i) = New Thread(AddressOf DoTheTask7)
- ' Assign a name to this thread, so that we can track its output.
- threads(i).Name = "Thread #" & i.ToString
- threads(i).Start()
- Next
-
- ' wait until all threads terminate
- For i = 1 To UBound(threads)
- threads(i).Join()
- Next
- End Sub
-
- Sub DoTheTask7()
- ' Print a lot of information to the console window.
- Dim i As Integer
- For i = 1 To 100
- Monitor.Enter(consoleLock)
- ' Split the output line in pieces.
- Console.Write("Message ")
- Console.Write("from ")
- Console.WriteLine(Thread.CurrentThread.Name)
- Monitor.Exit(consoleLock)
- Next
- End Sub
-
- ' this procedure tests the Monitor.Enter / Exit methods
-
- Sub TestMonitorTryEnter()
- ' Create five auxiliary threads.
- Dim threads(5) As Thread
-
- Dim i As Integer
- For i = 1 To 5
- threads(i) = New Thread(AddressOf DoTheTask8)
- ' Assign a name to this thread, so that we can track its output.
- threads(i).Name = "Thread #" & i.ToString
- threads(i).Start()
- Next
-
- ' wait until all threads terminate
- For i = 1 To UBound(threads)
- threads(i).Join()
- Next
- End Sub
-
- Sub DoTheTask8()
- ' Print a lot of information to the console window.
- Dim i As Integer
- For i = 1 To 100
- Do Until Monitor.TryEnter(consoleLock, 10)
- Console.WriteLine("{0} failed to acquire the lock", Thread.CurrentThread.Name)
- Loop
-
- ' Split the output line in pieces.
- Console.Write("Message ")
- Console.Write("from ")
- Console.WriteLine(Thread.CurrentThread.Name)
- ' Release the lock.
- Monitor.Exit(consoleLock)
- Next
- End Sub
-
- ' this procedure tests the Interlocked class
-
- Sub TestInterlocked()
- ' Create ten auxiliary threads.
- Dim threads(10) As Thread
-
- Dim i As Integer
- For i = 1 To 10
- threads(i) = New Thread(AddressOf DoTheTask9)
- ' Assign a name to this thread, so that we can track its output.
- threads(i).Name = "Thread #" & i.ToString
- threads(i).Start()
- Next
-
- ' wait until all threads terminate
- For i = 1 To UBound(threads)
- threads(i).Join()
- Next
- End Sub
-
- ' Increment and Decrement methods work with 32-bit integers.
- Dim lockCounter As Integer
-
- Sub DoTheTask9()
- ' Print a lot of information to the console window.
- Dim i As Integer
-
- ' Note that not all threads will print all the 100 messages
-
- For i = 1 To 100
- ' Increment the lock counter and return the new value.
- ' (Up to 4 threads are allowed to run in the critical section.)
- If Interlocked.Increment(lockCounter) <= 4 Then
- ' display number of threads in the critical section
- Console.WriteLine("Message from {0} ({1} threads running in critical section)", Thread.CurrentThread.Name, lockCounter)
- Thread.Sleep(10)
- End If
- ' Allow other threads to enter the critical section.
- Interlocked.Decrement(lockCounter)
- Next
- End Sub
-
- ' this procedure tests the Mutex object
-
- ' three mutex objects, representing three available resources
- Dim mutexes() As Mutex = {New Mutex(), New Mutex(), New Mutex()}
-
- Sub TestMutex()
- ' Create ten auxiliary threads.
- Dim threads(10) As Thread
-
- Dim i As Integer
- For i = 1 To 10
- threads(i) = New Thread(AddressOf DoTheTask10)
- ' Assign a name to this thread, so that we can track its output.
- threads(i).Name = "Thread #" & i.ToString
- threads(i).Start()
- Next
-
- ' wait until all threads terminate
- For i = 1 To UBound(threads)
- threads(i).Join()
- Next
- End Sub
-
- Sub DoTheTask10()
- ' Print a lot of information to the console window.
- Dim i As Integer
- For i = 1 To 100
- Dim mutexNdx As Integer = Mutex.WaitAny(mutexes)
- ' use only the resource representing the mutexNdx.
- Console.WriteLine("{0} is using Mutex #{1}", Thread.CurrentThread.Name, mutexNdx)
- mutexes(mutexNdx).ReleaseMutex()
- Next
- End Sub
-
- ' This procedure tests the ReaderWriterLock class
-
- Dim rwl As New ReaderWriterLock()
- Dim rnd As New Random()
-
- Sub TestReaderWriterLock()
- Dim i As Integer
- For i = 1 To 10
- Dim t As New Thread(AddressOf DoTheTask12)
- t.Name = i.ToString
- t.Start()
- Next
- Thread.Sleep(20000)
- End Sub
-
- Sub DoTheTask12()
- Dim i As Integer
- Dim tname As String = Thread.CurrentThread.Name()
- ' Perform 10 read or write operations. (Reads are more frequent.)
- For i = 1 To 10
- If rnd.NextDouble < 0.8 Then
- ' Attempt a read operation.
- rwl.AcquireReaderLock(Timeout.Infinite)
- Console.WriteLine("Thread {0} is reading", tname)
- Thread.Sleep(300)
- Console.WriteLine("Thread {0} completed the read operation", _
- tname)
- rwl.ReleaseReaderLock()
- Else
- ' Attempt a write operation.
- rwl.AcquireWriterLock(Timeout.Infinite)
- Console.WriteLine("Thread {0} is writing", tname)
- Thread.Sleep(300)
- Console.WriteLine("Thread {0} completed the write operation", _
- tname)
- rwl.ReleaseWriterLock()
- End If
- Next
- End Sub
-
- ' This procedure tests the AutoResetEvent class
-
- ' The shared AutoResetEvent object
- Public are As New AutoResetEvent(False)
- ' The ArrayList where matching filenames should be added
- Public filesAl As New ArrayList()
- ' The number of running threads
- Public searchingThreads As Integer
-
- Sub TestAutoResetEvent()
- ' Search the file in all the subdirectories of C:
- Dim dirname As String
- For Each dirname In System.IO.Directory.GetDirectories("C:\")
- Interlocked.Increment(searchingThreads)
- ' Create a new wrapper class, pointing to a subdirectory.
- Dim sf As New FileFinder(dirname, "*.zip")
- ' Create a new thread for that subdirectory only, and run it.
- Dim t As New Thread(AddressOf sf.StartSearch)
- t.Start()
- Next
-
- ' Remember how many results we have so far.
- Dim resCount As Integer = 0
- Do While searchingThreads > 0
- ' Wait until there are new results.
- are.WaitOne()
-
- ' Note that you should always use the SyncRoot property when using
- ' an ArrayList and other collectionlike objects as lock objects.
- SyncLock filesAl.SyncRoot
- ' Display names of all new results.
- Dim i As Integer
- For i = resCount To filesAl.Count - 1
- Console.WriteLine(filesAl(i))
- Next
- ' Remember that you've displayed these filenames.
- resCount = filesAl.Count
- End SyncLock
- Loop
- Console.WriteLine("")
- Console.WriteLine("Found {0} files", resCount)
- End Sub
-
- ' this procedure tests the ThreadPool class
-
- Sub TestThreadPool()
- Dim i As Integer
- For i = 1 To 20
- Try
- ' Create a new object for the next lightweight task.
- Dim task As New LightweightTask()
- ' Pass additional information to that object
- ' (Not used in this demo).
- task.SomeData = "other data"
- ' Run the task with a thread from the pool
- ' (Pass the counter as an argument).
- ThreadPool.QueueUserWorkItem( _
- New WaitCallback(AddressOf task.DoTheTask), i)
- Catch e As NotSupportedException
- Console.WriteLine("Failed (maybe a non-Windows 2000 system)")
- Exit Sub
- End Try
- Next
-
- ' Give all lightweight threads a chance to complete.
- Thread.Sleep(4000)
- End Sub
-
- ' this procedure tests the System.Timers.Timer class
-
- Dim WithEvents Timer As System.Timers.Timer
- Dim eventCount As Integer
-
- Sub TestServerTimer()
- ' Initialize the time to fire every second.
- ' (You can change it later through the Interval property.)
- Timer = New System.Timers.Timer(1000)
- ' True means it fires repeatedly, False means it fires only once.
- Timer.AutoReset = True
- ' Ensure the timer is enabled. (Same as Start method.)
- Timer.Enabled = True
-
- ' Pause here until 5 events fire.
- Do
- Console.WriteLine("Message from main thread")
- Thread.Sleep(100)
- Loop Until eventCount = 5
-
- ' Stop the timer (not really necessary in this example).
- Timer.Stop() ' Same as Timer.Enabled = False.
- ' Release all resources.
- Timer.Close()
- End Sub
-
- ' The Elapsed event
- Public Sub Timer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles Timer.Elapsed
- ' Display current system time in Output window.
- Console.WriteLine("Event raised at {0}", e.SignalTime)
- ' Remember how many events fired so far.
- eventCount += 1
- End Sub
-
- ' this procedure tests the System.Threading.Timer
-
- Sub TestThreadingTimer()
- ' Get the first callback after 1 second
- Dim dueTime As New TimeSpan(0, 0, 1)
- ' get additional callbacks every half a second
- Dim period As New TimeSpan(0, 0, 0, 0, 500)
- ' create the timer
- Dim t As New System.Threading.Timer(New TimerCallback(AddressOf TimerProc), Nothing, dueTime, period)
-
- ' wait for 5 seconds in this demo.
- Thread.Sleep(5000)
-
- ' destroy the timer
- t.Dispose()
- End Sub
-
- ' the callback procedure
-
- Sub TimerProc(ByVal state As Object)
- ' Display current system time in Output window.
- Console.WriteLine("Callback proc called at {0}", Date.Now)
- End Sub
-
- ' this procedure tests the Synchronization attribute
-
- Dim disp As New Display()
-
- Sub TestSynchronizationAttribute()
- Dim i As Integer
- Dim threads(10) As Thread
- Dim o As New Object()
-
- For i = 1 To 10
- threads(i) = New Thread(AddressOf DoTheTask11)
- threads(i).Name = "Thread #" & i.ToString
- threads(i).Start()
- Next
-
- ' wait for all threads to terminate.
- For i = 1 To UBound(threads)
- threads(i).Join()
- Next
- End Sub
-
- Sub DoTheTask11()
- ' Print a lot of information to the Output window.
- Dim i As Integer
- For i = 1 To 20
- disp.DisplayData()
- Next
- End Sub
-
- End Module
-
-